package com.mfw.springboot.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mfw.springboot.common.DataGroupByDateDTO;
import com.mfw.springboot.common.ErrorCode;
import com.mfw.springboot.constant.CommonConstant;
import com.mfw.springboot.exception.ThrowUtils;
import com.mfw.springboot.mapper.EvaluationMapper;
import com.mfw.springboot.model.dto.evaluation.EvaluationQueryRequest;
import com.mfw.springboot.model.entity.Evaluation;
import com.mfw.springboot.model.entity.TrainingPlan;
import com.mfw.springboot.model.entity.User;
import com.mfw.springboot.model.vo.EvaluationVO;
import com.mfw.springboot.model.vo.TrainingPlanVO;
import com.mfw.springboot.model.vo.UserVO;
import com.mfw.springboot.service.EvaluationService;
import com.mfw.springboot.service.TrainingPlanService;
import com.mfw.springboot.service.UserService;
import com.mfw.springboot.utils.DateUtils;
import com.mfw.springboot.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 评价服务实现
 *
 * @author mfw
 * @from <a href="https://gitee.com/hanhuaifei/projects">我的gitee</a>
 * @Date 2024/9/26
 */
@Service
@Slf4j
public class EvaluationServiceImpl extends ServiceImpl<EvaluationMapper, Evaluation> implements EvaluationService {

    @Resource
    private UserService userService;

    @Resource
    private TrainingPlanService trainingPlanService;

    /**
     * 校验数据
     *
     * @param evaluation
     * @param add        对创建的数据进行校验
     */
    @Override
    public void validEvaluation(Evaluation evaluation, boolean add) {
        ThrowUtils.throwIf(evaluation == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        String content = evaluation.getContent();
        BigDecimal score = evaluation.getScore();

        // 创建数据时，参数不能为空
        if (add) {
            // 补充校验规则
            ThrowUtils.throwIf(StringUtils.isBlank(content), ErrorCode.PARAMS_ERROR);
        }
        // 修改数据时，有参数则校验
        // 补充校验规则
        if (StringUtils.isNotBlank(content)) {
            ThrowUtils.throwIf(content.length() > 80, ErrorCode.PARAMS_ERROR, "内容过长");
        }
        // 定义上下限
        BigDecimal lowerBound = BigDecimal.ZERO; // 0
        BigDecimal upperBound = new BigDecimal("10");
        if (score != null) {
            ThrowUtils.throwIf(!(score.compareTo(lowerBound) >= 0 && score.compareTo(upperBound) <= 0), ErrorCode.PARAMS_ERROR, "评分不在0~10之间");
        }
    }

    /**
     * 获取查询条件
     *
     * @param evaluationQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Evaluation> getQueryWrapper(EvaluationQueryRequest evaluationQueryRequest) {
        QueryWrapper<Evaluation> queryWrapper = new QueryWrapper<>();
        if (evaluationQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = evaluationQueryRequest.getId();
        String content = evaluationQueryRequest.getContent();
        Long coachId = evaluationQueryRequest.getCoachId();
        Long studentId = evaluationQueryRequest.getStudentId();
        Long planId = evaluationQueryRequest.getPlanId();

        String sortField = evaluationQueryRequest.getSortField();
        String sortOrder = evaluationQueryRequest.getSortOrder();

        //  补充需要的查询条件
        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(content), "content", content);

        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(coachId), "coach_id", coachId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(studentId), "student_id", studentId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(planId), "plan_id", planId);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取评价封装
     *
     * @param evaluation
     * @param request
     * @return
     */
    @Override
    public EvaluationVO getEvaluationVO(Evaluation evaluation, HttpServletRequest request) {
        // 对象转封装类
        EvaluationVO evaluationVO = EvaluationVO.objToVo(evaluation);

        // 可以根据需要为封装对象补充值，不需要的内容可以删除
        // region 可选
        // 1. 关联查询学员信息
        Long studentId = evaluation.getStudentId();
        User student = null;
        if (studentId != null && studentId > 0) {
            student = userService.getById(studentId);
        }
        UserVO studentVO = userService.getUserVO(student);
        evaluationVO.setStudent(studentVO);
        // 2. 关联查询教练信息
        Long coachId = evaluation.getCoachId();
        User coach = null;
        if (coachId != null && coachId > 0) {
            coach = userService.getById(coachId);
        }
        UserVO coachVO = userService.getUserVO(coach);
        evaluationVO.setCoach(coachVO);
        // 3. 关联查询训练计划信息
        Long planId = evaluation.getPlanId();
        TrainingPlan trainingPlan = null;
        if (planId != null && planId > 0) {
            trainingPlan = trainingPlanService.getById(planId);

        }
        TrainingPlanVO trainingPlanVO = trainingPlanService.getTrainingPlanVO(trainingPlan, request);
        evaluationVO.setTrainingPlan(trainingPlanVO);

        return evaluationVO;
    }

    /**
     * 分页获取评价封装
     *
     * @param evaluationPage
     * @param request
     * @return
     */
    @Override
    public Page<EvaluationVO> getEvaluationVOPage(Page<Evaluation> evaluationPage, HttpServletRequest request) {
        List<Evaluation> evaluationList = evaluationPage.getRecords();
        Page<EvaluationVO> evaluationVOPage = new Page<>(evaluationPage.getCurrent(), evaluationPage.getSize(), evaluationPage.getTotal());
        if (CollUtil.isEmpty(evaluationList)) {
            return evaluationVOPage;
        }
        // 对象列表 => 封装对象列表
        List<EvaluationVO> evaluationVOList = evaluationList.stream().map(evaluation -> {
            return EvaluationVO.objToVo(evaluation);
        }).collect(Collectors.toList());

        // TODO 可以根据需要为封装对象补充值，不需要的内容可以删除
        // region 可选
        // 1. 关联查询学生信息
        Set<Long> studentIdSet = evaluationList.stream().map(Evaluation::getStudentId).collect(Collectors.toSet());
        Map<Long, List<User>> studentIdUserListMap = userService.listByIds(studentIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 2. 关联查询教练信息
        Set<Long> coachIdSet = evaluationList.stream().map(Evaluation::getCoachId).collect(Collectors.toSet());
        Map<Long, List<User>> coachIdUserListMap = userService.listByIds(coachIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 3. 关联查询训练计划信息
        Set<Long> planIdSet = evaluationList.stream().map(Evaluation::getPlanId).collect(Collectors.toSet());
        Map<Long, List<TrainingPlan>> planIdTrainingPlanListMap = trainingPlanService.listByIds(planIdSet).stream()
                .collect(Collectors.groupingBy(TrainingPlan::getId));
        // 填充信息
        evaluationVOList.forEach(evaluationVO -> {
            Long studentId = evaluationVO.getStudentId();
            Long coachId = evaluationVO.getCoachId();
            Long planId = evaluationVO.getPlanId();
            //学员
            User student = null;
            if (studentIdUserListMap.containsKey(studentId)) {
                student = studentIdUserListMap.get(studentId).get(0);
            }
            evaluationVO.setStudent(userService.getUserVO(student));
            //教练
            User coach = null;
            if (coachIdUserListMap.containsKey(coachId)) {
                coach = coachIdUserListMap.get(coachId).get(0);
            }
            evaluationVO.setCoach(userService.getUserVO(coach));
            //训练计划
            TrainingPlan plan = null;
            if (planIdTrainingPlanListMap.containsKey(planId)) {
                plan = planIdTrainingPlanListMap.get(planId).get(0);
            }
            evaluationVO.setTrainingPlan(trainingPlanService.getTrainingPlanVO(plan, request));
        });
        // endregion

        evaluationVOPage.setRecords(evaluationVOList);
        return evaluationVOPage;
    }

    /**
     * 分按日期分组查询评价新增数量
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    @Override
    public List<DataGroupByDateDTO> countByDay(Date beginDate, Date endDate) {
        QueryWrapper<Evaluation> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m-%d') AS day", "COUNT(1) AS num");
        queryWrapper.ge("create_time", beginDate);
        queryWrapper.le("create_time", endDate);
        queryWrapper.groupBy("day");
        queryWrapper.orderByAsc("day");
        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);
        // 映射到 DataGroupByDateDTO
        return results.stream().map(result -> {
            DataGroupByDateDTO dto = new DataGroupByDateDTO();
            dto.setDay(DateUtils.parse(result.get("day").toString(), DateUtils.FMT_YMD));
            dto.setNum((Long) result.get("num"));
            return dto;
        }).collect(Collectors.toList());
    }

}
